From 8c867b0aab8be77cd23f9897e4745c2486bc8349 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 12 Jul 2018 00:39:38 +0100 Subject: [PATCH] HID: Avoid ABI change in 4.17.6 Commit 8f732850df1b "HID: core: allow concurrent registration of drivers" introduced atomic bit-operations on hid_device::status, and changed its type from unsigned int to unsigned long as required for those operations. Revert the type change and use cmpxchg() for the bit-operations, since it supports unsigned int. Gbp-Pq: Topic debian Gbp-Pq: Name hid-avoid-abi-change-in-4.17.6.patch --- drivers/hid/hid-core.c | 32 ++++++++++++++++++++++++++++++-- include/linux/hid.h | 2 +- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c1ce4baeeac..43af36355e1 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1929,6 +1929,34 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv) return hid_match_device(hdev, hdrv) != NULL; } +static void clear_status_flag(unsigned int flag, unsigned int *status) +{ + unsigned int expect, old; + + expect = READ_ONCE(*status); + for (;;) { + old = cmpxchg(status, expect, expect & ~flag); + if (old == expect) + break; + expect = old; + } +} + +static bool test_and_set_status_flag(unsigned int flag, unsigned int *status) +{ + unsigned int expect, old; + + expect = READ_ONCE(*status); + for (;;) { + old = cmpxchg(status, expect, expect | flag); + if (old == expect) + break; + expect = old; + } + + return old & flag; +} + static int hid_device_probe(struct device *dev) { struct hid_driver *hdrv = to_hid_driver(dev->driver); @@ -1942,7 +1970,7 @@ static int hid_device_probe(struct device *dev) } hdev->io_started = false; - clear_bit(ffs(HID_STAT_REPROBED), &hdev->status); + clear_status_flag(HID_STAT_REPROBED, &hdev->status); if (!hdev->driver) { id = hid_match_device(hdev, hdrv); @@ -2208,7 +2236,7 @@ static int __hid_bus_reprobe_drivers(struct device *dev, void *data) if (hdev->driver == hdrv && !hdrv->match(hdev, hid_ignore_special_drivers) && - !test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) + !test_and_set_status_flag(HID_STAT_REPROBED, &hdev->status)) return device_reprobe(dev); return 0; diff --git a/include/linux/hid.h b/include/linux/hid.h index 2a4c0900e46..4eca5e3ecec 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -569,7 +569,7 @@ struct hid_device { /* device report descriptor */ bool battery_avoid_query; #endif - unsigned long status; /* see STAT flags above */ + unsigned int status; /* see STAT flags above */ unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned quirks; /* Various quirks the device can pull on us */ bool io_started; /* If IO has started */ -- 2.30.2